package com.kamistoat.meimeimall.meimeimallware.service.impl;

import com.kamistoat.meimeimall.common.utils.PageUtils;
import com.kamistoat.meimeimall.common.utils.Query;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.kamistoat.meimeimall.common.To.RabbitMQTo.OrderTo;
import com.kamistoat.meimeimall.common.To.RabbitMQTo.StockLockedTo;
import com.kamistoat.meimeimall.common.annotation.ClearCache;
import com.kamistoat.meimeimall.common.annotation.WithCache;
import com.kamistoat.meimeimall.common.constant.WareConstant;
import com.kamistoat.meimeimall.common.exception.BizCodeEnum;
import com.kamistoat.meimeimall.common.exception.RRException;
import com.kamistoat.meimeimall.common.utils.R;
import com.kamistoat.meimeimall.meimeimallware.dao.WareOrderTaskDao;
import com.kamistoat.meimeimall.meimeimallware.dao.WareOrderTaskDetailDao;
import com.kamistoat.meimeimall.meimeimallware.entity.WareOrderTaskDetailEntity;
import com.kamistoat.meimeimall.meimeimallware.entity.WareOrderTaskEntity;
import com.kamistoat.meimeimall.meimeimallware.enums.WareTaskStatusEnum;
import com.kamistoat.meimeimall.meimeimallware.feign.OrderFeignService;
import com.kamistoat.meimeimall.meimeimallware.feign.ProductFeignService;
import com.kamistoat.meimeimall.meimeimallware.service.WareOrderTaskDetailService;
import com.kamistoat.meimeimall.meimeimallware.service.WareOrderTaskService;
import com.kamistoat.meimeimall.meimeimallware.dao.WareSkuDao;
import com.kamistoat.meimeimall.common.To.wareTo.LockOrderItemWareTo;
import com.kamistoat.meimeimall.meimeimallware.vo.SkuWareHasStockVo;
import com.kamistoat.meimeimall.common.To.wareTo.LockOrderWareTo;
import com.kamistoat.meimeimall.meimeimallware.vo.SkuWareVo;
import com.kamistoat.meimeimall.meimeimallware.vo.WareOrderTaskAndDetailVo;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.kamistoat.meimeimall.meimeimallware.entity.WareSkuEntity;
import com.kamistoat.meimeimall.meimeimallware.service.WareSkuService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

@Service("wareSkuService")
public class WareSkuServiceImpl extends ServiceImpl<WareSkuDao, WareSkuEntity> implements WareSkuService {

    @Autowired
    ProductFeignService productFeignService;
    @Autowired
    OrderFeignService orderFeignService;
    @Autowired
    RabbitTemplate rabbitTemplate;
    @Autowired
    WareOrderTaskService wareOrderTaskService;
    @Autowired
    WareOrderTaskDetailService wareOrderTaskDetailService;
    @Autowired
    WareOrderTaskDetailDao wareOrderTaskDetailDao;
    @Autowired
    WareSkuDao wareSkuDao;
    @Autowired
    WareOrderTaskDao wareOrderTaskDao;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<WareSkuEntity> page = this.page(
                new Query<WareSkuEntity>().getPage(params),
                new QueryWrapper<WareSkuEntity>()
        );

        return new PageUtils(page);
    }

    /**
     * 自己的方法，根据SKUID和仓库Id查出库存
     *
     * @param params 查询条件
     * @return 分页封装
     */
    @Override
    public PageUtils queryPageByWareSkuInfo(Map<String, Object> params) {
        QueryWrapper<WareSkuEntity> wrapper = new QueryWrapper<>();
        if (!StringUtils.isEmpty(params.get("skuId"))) {
            wrapper.eq("sku_id", params.get("skuId"));
        }
        if (!StringUtils.isEmpty(params.get("wareId"))) {
            wrapper.eq("ware_id", params.get("wareId"));
        }
        IPage<WareSkuEntity> page = this.page(new Query<WareSkuEntity>().getPage(params), wrapper);
        return new PageUtils(page);
    }

    /**
     * 为指定商品添加库存
     *
     * @param skuId  商品skuId
     * @param wareId 商品仓库Id
     * @param skuNum 商品库存
     */
    @Override
    public void addStock(Long skuId, Long wareId, Integer skuNum) {
        WareSkuEntity wareSkuEntity = baseMapper.selectOne(new QueryWrapper<WareSkuEntity>().
                eq("sku_id", skuId).eq("ware_id", wareId));
        if (wareSkuEntity != null) {
            wareSkuEntity.setStock(wareSkuEntity.getStock() + skuNum);
            baseMapper.updateById(wareSkuEntity);
        } else {
            // 如果还没有这条库存关系，直接用save
            WareSkuEntity skuEntity = new WareSkuEntity();
            skuEntity.setSkuId(skuId);
            skuEntity.setSkuName(productFeignService.getSkuFeign(skuId).getSkuName());
            skuEntity.setStock(skuNum);
            skuEntity.setWareId(wareId);
            skuEntity.setStockLocked(0);
            this.save(skuEntity);
        }
    }

    /**
     * 带缓查询一件商品的库存列表。
     *
     * @param skuId
     * @return
     */
    @Override
    @WithCache(prefix = "ware:list:#skuId", isList = true, returnType = WareSkuEntity.class)
    public List<WareSkuEntity> getWareSkuList(Long skuId) {
        return this.list(new QueryWrapper<WareSkuEntity>().eq("sku_id", skuId));
    }

    /**
     * 下单时，真正的数据库库存扣减以任务引擎的思路来做。该方法根据订单-库存工单执行数据库库存扣减。
     * 注意，该方法不需要以事务执行，只需要让内部每个商品的扣减是事务即可。
     * 因为通过了预扣减，则最终一定是需要做数据库库存扣减的，没必要来来回回的回滚。
     * @param wareOrderTaskAndDetailVo
     */
    @Override
    public void lockWareOnCreate(WareOrderTaskAndDetailVo wareOrderTaskAndDetailVo) {
        WareOrderTaskEntity taskInDatabase = wareOrderTaskService.getById(wareOrderTaskAndDetailVo.getId());
        // 幂等消费保障。
        if(taskInDatabase != null && !taskInDatabase.getTaskStatus().equals(WareTaskStatusEnum.WAITINGDEDUCTING.getCode())) {
            return;
        }
        boolean allSuccess = true;
        // 即便订单-库存工单是待扣减，内部的某些商品单项可能是已经完成的，这里也要做幂等消费保障
        for (WareOrderTaskDetailEntity detailEntity : wareOrderTaskAndDetailVo.getDetailEntityList()) {
            WareOrderTaskDetailEntity detailInDatabase = wareOrderTaskDetailService.getById(detailEntity.getId());
            if(detailInDatabase.getLockStatus().equals(WareTaskStatusEnum.WAITINGDEDUCTING.getCode())) {
                // 如果该单商品库存操作单的状态为待扣减，那么就对其进行真正的扣减。其他的状态下都是幂等消费
                try {
                    lockSingleWare(detailEntity);
                }catch (Exception e) {
                    // 如果某个单项商品异常，不要管，也不要回滚之前成功扣减的，而是跳过，之后重新消费
                    allSuccess = false;
                }
            }
        }
        if(!allSuccess) {
            throw new RRException("该订单-库存工单并未完全扣减成功，不要ACK，重新投递，重新消费");
        }
    }

    @Transactional
    public void lockSingleWare(WareOrderTaskDetailEntity detailEntity) {
        if(detailEntity.getSeckillSessionId() != null && detailEntity.getSeckillSessionId() != 0L) {
            // 促销商品就去修改促销商品库存

        }else{
            // 普通商品就去修改普通商品库存
        }
    }


    /**
     * <b>已弃用</b>
     */
    @Override
    public void orderLockStock(LockOrderWareTo lockOrderWareTo) {
        WareOrderTaskEntity wareOrderTaskEntity = new WareOrderTaskEntity();
        /**
         * 1. 查询每个商品的 WareSkuId 列表，因为每个商品会在多个仓库中存储
         */
        // 获取订单中所有商品小项的信息
        List<LockOrderItemWareTo> lockList = lockOrderWareTo.getLockList();
        // 查询每个商品都在那几个仓库有货。所有商品的分布情况制作成一个List
        List<SkuWareHasStockVo> skuWareHasStockVoList = lockList.stream().map(orderItemVo -> {
            SkuWareHasStockVo skuWareHasStockVo = new SkuWareHasStockVo();
            // 获取当前商品Id
            Long skuId = orderItemVo.getSkuId();
            skuWareHasStockVo.setSkuId(skuId);
            // 设置当前商品希望锁定几件库存
            skuWareHasStockVo.setNum(orderItemVo.getCount());
            // 查询商品在哪几个仓库储存
            List<SkuWareVo> wareSkuIdList = baseMapper.listWareHasSkuStock(skuId);
            skuWareHasStockVo.setSkuWareVoList(wareSkuIdList);
            return skuWareHasStockVo;
        }).collect(Collectors.toList());


        /**
         * 2. 开始在库存足够的仓库中锁定库存
         */
        List<WareOrderTaskDetailEntity> wareOrderTaskDetailEntityList = new ArrayList<>();
        // 遍历所有商品分布情况的列表
        for (SkuWareHasStockVo skuWareHasStockVo : skuWareHasStockVoList) {
            boolean skuLock = false;  // 用于标记当前商品小项是否被锁定成功
            // 对每一件商品的分布情况进行遍历，判断它的哪一个仓库能够扣除掉库存
            Long skuId = skuWareHasStockVo.getSkuId();
            List<SkuWareVo> skuWareVoList = skuWareHasStockVo.getSkuWareVoList();
            // 对每一个仓库检查库存是否能扣除，哪个扣成功了直接去扣下一个订单小项
            // 这里偷了个懒，只要有一件商品扣库存失败，整个锁定库存的操作都退出。

            // 如果某一件商品连仓库都没有，那一定是扣库存失败。直接抛出当前 skuId 的异常
            if (skuWareVoList == null || skuWareVoList.size() == 0) {
                throw new RRException(BizCodeEnum.NO_STOCK_EXCEPTION.getMessage() + ":" + skuId, BizCodeEnum.NO_STOCK_EXCEPTION.getCode());
            }

            for (SkuWareVo skuWareVo : skuWareVoList) {
                // 依次去当前订单小项的仓库中扣
                // 使用 UPDATE 自带排他锁，保证不会超卖。返回值count为操作成功的行数，为1即为锁定成功，为0即为锁定失败
                Long count = this.lockSkuStock(skuId, skuWareVo.getWareSkuId(), skuWareHasStockVo.getNum());
                if (count == 1) {
                    // 当前仓库锁定成功
                    skuLock = true;
                    // 创建锁库存工单
                    WareOrderTaskDetailEntity wareOrderTaskDetailEntity = new WareOrderTaskDetailEntity();
                    wareOrderTaskDetailEntity.setSkuId(skuWareHasStockVo.getSkuId());  // 当前商品SKu
                    wareOrderTaskDetailEntity.setWareId(skuWareVo.getWareId());  // 当前在哪个仓库进行锁定
                    wareOrderTaskDetailEntity.setSkuNum(skuWareHasStockVo.getNum());  // 当前锁定了多少件库存
                    wareOrderTaskDetailEntity.setTaskId(wareOrderTaskEntity.getId());  // 锁定工单对应哪一张库存-订单工单
                    wareOrderTaskDetailEntity.setLockStatus(WareConstant.StockLockStatus.LOCKED.getCode());  // 声明库存工单状态 —— 已锁定
                    wareOrderTaskDetailEntityList.add(wareOrderTaskDetailEntity);
                    break;  // 跳出当前商品小项的锁定，去下一个
                }
                // if执行不成功，就是当前仓库锁定失败，尝试下一个仓库
            }
            // 当前订单小项全部仓库遍历结束后，判断是否锁成功。没成功同样全部退出
            if (!skuLock) {
                throw new RRException(BizCodeEnum.NO_STOCK_EXCEPTION.getMessage() + ":" + skuId, BizCodeEnum.NO_STOCK_EXCEPTION.getCode());
            }
        }

        /**
         * 3. 将锁定库存工单保存入库
         */
        for (WareOrderTaskDetailEntity wareOrderTaskDetailEntity : wareOrderTaskDetailEntityList) {
            // 将锁库存工单保存到数据库
            wareOrderTaskDetailService.save(wareOrderTaskDetailEntity);
            // 向RabbitMQ的延迟队列发送消息
            // 注意，整个锁定库存操作是存在回滚操作的，但是MQ可没有。之后MQ延时队列到期时，根据消息中的 库存-订单工单Id
            // 1. 若数据库查询不到，则说明在一阶段即失败，被SB的事务自动回滚并删除了所有数据，则不做任何处理.
            // 2. 查询得到，但状态非成功扣减，则也不做任何处理.
            StockLockedTo stockLockedTo = new StockLockedTo();
            stockLockedTo.setWareOrderId(wareOrderTaskEntity.getId());  // 向消息中心保存 库存-订单工单 Id
            stockLockedTo.setStockId(wareOrderTaskDetailEntity.getId());  // 向消息中心保存 锁定工单 id
            rabbitTemplate.convertAndSend(
                    "stock-event-exchange",
                    "stock.locked",
                    stockLockedTo
            );
        }
    }

    /**
     * 尝试锁定商品skuId主键为wareSkuId的库存。在锁定成功后需要删除缓存.
     *
     * @param skuId     商品skuId
     * @param wareSkuId 主键wareSkuId
     * @param lockNum   锁定的库存值
     * @return 成功操作的行数。
     */
    @ClearCache(prefix = "ware:list:#skuId")
    @Transactional
    public Long lockSkuStock(Long skuId, Long wareSkuId, int lockNum) {
        return baseMapper.lockSkuStock(wareSkuId, lockNum);
    }

    /**
     * 下单锁定库存事务分支的提交动作。
     * 若能执行到commit，则必然所有表都已经建立成功。
     *
     * @param lockOrderWareTo LockOrderWareTo
     */
    @Transactional
    @Override
    public void orderLockStockCommit(LockOrderWareTo lockOrderWareTo) {
        /**
         * 提交时，只需要修改两处：
         * 1. 将库存的lock值扣除
         * 2. 修改库存锁定工单的状态
         * 3. 修改库存-订单工单的状态.
         *
         * 不对。此时就算提交了也应该保持锁定状态，锁定库存应该在真正支付后才真正扣除。所以这里的commit完全不做就行了。
         */
//        // 获取库存-订单工单的 主键和状态
//        WareOrderTaskEntity wareOrderTaskEntity =
//                wareOrderTaskService.getOne(new QueryWrapper<WareOrderTaskEntity>().select("id", "task_status").eq("order_sn", lockOrderWareTo.getOrderSn()));
//        // 防悬挂检查。如果已经执行过全局提交，则直接跳过
//        if (wareOrderTaskEntity.getTaskStatus().equals(WareConstant.StockLockStatus.LOCKED.getCode())) {
//            // 根据上Id查出库存锁定工单
//            List<WareOrderTaskDetailEntity> wareDetailEntityList =
//                    wareOrderTaskDetailService.getBaseMapper().selectList(new QueryWrapper<WareOrderTaskDetailEntity>().eq("task_id", wareOrderTaskEntity.getId()));
//            for (WareOrderTaskDetailEntity detailEntity : wareDetailEntityList) {
//                // 防悬挂检查
//                if (detailEntity.getLockStatus().equals(WareConstant.StockLockStatus.LOCKED.getCode())) {
//                    // 1. 根据库存锁定工单真实扣除Lock值
//                    // 同样，UPDATE自带排他锁
//                    wareSkuDao.lockSkuStockCommit(detailEntity.getSkuId(), detailEntity.getWareId(), detailEntity.getSkuNum());
//                    // 2. 修改库存锁定工单状态
//                    detailEntity.setLockStatus(WareConstant.StockLockStatus.REDUCED.getCode());
//                }
//            }
//            wareOrderTaskDetailService.updateBatchById(wareDetailEntityList);
//
//            // 最后修改库存-订单工单的状态为真正扣除。自带排他锁
//            wareOrderTaskService.update(new UpdateWrapper<WareOrderTaskEntity>()
//                    .set("task_status", WareConstant.StockLockStatus.REDUCED.getCode())
//                    .eq("id", wareOrderTaskEntity.getId()));
//        }
    }

    /**
     * 下单锁定库存事务分支的回滚动作。
     * 若执行回滚，有可能一阶段都没有完成，也有可能是之后的分布式事务异常导致整个全局事务回滚。
     * 如果是一阶段都没有完成，那无所谓，SpringBoot自己的@Transactional能保证回滚，所有的数据自动删除。
     * 如果是之后的异常，则需要:
     * 1. 将库存的lock值补回库存
     * 2. 删除所有一阶段创建的表
     *
     * @param lockOrderWareTo LockOrderWareTo
     */
    @Override
    public void orderLockStockRollback(LockOrderWareTo lockOrderWareTo) {
        WareOrderTaskEntity wareOrderTaskEntity =
                wareOrderTaskService.getOne(new QueryWrapper<WareOrderTaskEntity>().select("id", "task_status").eq("order_sn", lockOrderWareTo.getOrderSn()));
        // 查不到，说明是一阶段即失败，数据已被SB自动删除。则不做任何操作.
        // 防悬挂检查。如果查得到，状态必须为锁定状态
        if (wareOrderTaskEntity != null && wareOrderTaskEntity.getTaskStatus().equals(WareConstant.StockLockStatus.LOCKED.getCode())) {
            // 根据上Id查出库存锁定工单
            List<WareOrderTaskDetailEntity> wareDetailEntityList =
                    wareOrderTaskDetailService.getBaseMapper().selectList(new QueryWrapper<WareOrderTaskDetailEntity>().eq("task_id", wareOrderTaskEntity.getId()));
            for (WareOrderTaskDetailEntity detailEntity : wareDetailEntityList) {
                // 防悬挂检查
                if (detailEntity.getLockStatus().equals(WareConstant.StockLockStatus.LOCKED.getCode())) {
                    // 1. 根据库存锁定工单，扣除锁定值，恢复真实库存值
                    // 同样，UPDATE自带排他锁
                    wareSkuDao.lockSkuStockRollback(detailEntity.getSkuId(), detailEntity.getWareId(), detailEntity.getSkuNum());
                    // 2. 修改库存锁定工单状态
                    detailEntity.setLockStatus(WareConstant.StockLockStatus.RELEASED.getCode());
                }
            }
            wareOrderTaskDetailService.updateBatchById(wareDetailEntityList);

            // 最后修改库存-订单工单的状态为真正扣除。自带排他锁
            wareOrderTaskService.update(new UpdateWrapper<WareOrderTaskEntity>()
                    .set("task_status", WareConstant.StockLockStatus.RELEASED.getCode())
                    .eq("id", wareOrderTaskEntity.getId()));
        }
    }

    /**
     * 监听死信队列，当2分钟到了以后主动去执行库存解锁
     *
     * @param stockLockedTo
     */
    @Override
    public void stockLockedRelease(StockLockedTo stockLockedTo) {
        /**
         * 获取到 库存-订单 id，先从数据库查看是否还存在这条工单记录。如果没有则说明库存服务有异常，已经被本地事务所回滚，直接不需要进行任何操作
         * 如果工单还在，那么根据订单sn去数据库看看订单还在不在，如果不在说明订单有异常被回滚了，回滚解锁库存。如果订单还在，看看是否未支付被取消，是的话也回滚解锁库存
         */
        Long wareOrderId = stockLockedTo.getWareOrderId();
        WareOrderTaskEntity wareOrderTaskEntity = wareOrderTaskService.getById(wareOrderId);
        if (wareOrderTaskEntity == null) {
            // 如果 库存-订单 工单根本就不存在，说明库存本地事务已经回滚了，不需要做任何事情
            return;
        } else {
            // 如果工单存在，先去看看订单在不在
            String orderSn = wareOrderTaskEntity.getOrderSn();
            R orderBySn = orderFeignService.getOrderBySn(orderSn);
            if ((int) orderBySn.get("code") == 1 || (int) orderBySn.get("status") == 4) {
                // 订单都不存在了，直接执行库存回滚
                // 订单存在，但是被超时关闭或无效，也执行库存回滚
                // 或运算只要第一个成功后面的条件直接就不看了，不会出错
                Long stockId = stockLockedTo.getStockId();
                WareOrderTaskDetailEntity lockDetail = wareOrderTaskDetailService.getById(stockId);  // 只要到了这一步，一定存在的，当然再判断一下也可以
                if (lockDetail != null && lockDetail.getLockStatus() == 1) {
                    // 如果工单状态是锁定，解锁库存
                    // 注意这里很重要，一定要判断工单是否是锁定。因为之后会有主动被动两种机制互相补充解锁，这里必须进行判断防止重复解锁
                    baseMapper.stockLockedRelease(lockDetail.getSkuId(), lockDetail.getWareId(), lockDetail.getSkuNum());
                    // 更改工单状态后保存
                    lockDetail.setLockStatus(2);
                    wareOrderTaskDetailService.updateById(lockDetail);
                    System.out.println("解锁" + lockDetail.getSkuId() + "号商品库存");
                }
            }
        }
    }

    /**
     * 当接受到订单服务发送来的订单取消事件，立刻执行解锁库存
     *
     * @param orderTo
     */
    @Transactional
    @Override
    public void orderRelease(OrderTo orderTo) {
        // 不用管订单状态了，直接不用管了。非要再查一遍也行
        R orderBySn = orderFeignService.getOrderBySn(orderTo.getOrderSn());
        if ((int) orderBySn.get("code") == 1 || (int) orderBySn.get("status") == 4) {
            // 直接去查 库存-订单工单
            WareOrderTaskEntity wareOrderTaskEntity =
                    wareOrderTaskService.getOne(
                            new QueryWrapper<WareOrderTaskEntity>().eq("order_sn", orderTo.getOrderSn()));
            if (wareOrderTaskEntity != null) {
                // 非空，直接去查大工单对应的所有锁定工单(且再进行一次检测，状态得是未解锁)
                List<WareOrderTaskDetailEntity> lockDetailList = wareOrderTaskDetailDao.selectList(
                        new QueryWrapper<WareOrderTaskDetailEntity>().
                                eq("task_id", wareOrderTaskEntity.getId()).
                                eq("lock_status", 1));
                if (lockDetailList != null && lockDetailList.size() > 0) {
                    // 对所有的锁定工单进行解锁
                    for (WareOrderTaskDetailEntity lockDetail : lockDetailList) {
                        baseMapper.stockLockedRelease(lockDetail.getSkuId(), lockDetail.getWareId(), lockDetail.getSkuNum());
                        // 更改工单状态后保存
                        lockDetail.setLockStatus(2);
                        wareOrderTaskDetailService.updateById(lockDetail);
                        System.out.println("解锁" + lockDetail.getSkuId() + "号商品库存");
                    }
                }
            }
        }
    }

    /**
     * 支付成功。则释放被锁定的库存，真正扣减掉该库存.
     * 1. 改库存
     * 2. 改订单-库存 工单状态
     * 3. 改库存工单状态
     *
     * @param orderSn 订单SN
     */
    @Override
    @Transactional
    public void handleSuccessPayWare(String orderSn) {
        // 订单-库存工单
        WareOrderTaskEntity taskEntity = wareOrderTaskService.getOne(
                new QueryWrapper<WareOrderTaskEntity>().select("id").eq("order_sn", orderSn));
        // 库存工单列表
        List<WareOrderTaskDetailEntity> detailList = wareOrderTaskDetailService.getBaseMapper().selectList(
                new QueryWrapper<WareOrderTaskDetailEntity>().eq("task_id", taskEntity.getId()));
        // 释放被锁定的库存
        for (WareOrderTaskDetailEntity wareOrderTaskDetailEntity : detailList) {
            // 修改库存
            wareSkuDao.successPayAndDeductStock(
                    wareOrderTaskDetailEntity.getSkuId(),
                    wareOrderTaskDetailEntity.getSkuNum(),
                    wareOrderTaskDetailEntity.getWareId());
            // 修改库存工单状态
            wareOrderTaskDetailService.update(new UpdateWrapper<WareOrderTaskDetailEntity>().set("lock_status", WareConstant.StockLockStatus.REDUCED.getCode()));
        }
        // 修改订单-库存工单状态
        wareOrderTaskService.update(new UpdateWrapper<WareOrderTaskEntity>().set("lock_status", WareConstant.StockLockStatus.REDUCED.getCode()));
    }

    /**
     * 支付成功时，从锁定的库存值中扣除，真正扣除库存 回滚动作。
     * 检查库存工单状态，如果已经是成功扣除，则重新加回锁定值上
     *
     * @param orderSn 订单sn
     */
    @Override
    public void handleSuccessPayWareRollback(String orderSn) {
        // 订单-库存工单
        WareOrderTaskEntity taskEntity = wareOrderTaskService.getOne(
                new QueryWrapper<WareOrderTaskEntity>().select("id").eq("order_sn", orderSn));
        // 库存工单列表
        List<WareOrderTaskDetailEntity> detailList = wareOrderTaskDetailService.getBaseMapper().selectList(
                new QueryWrapper<WareOrderTaskDetailEntity>().eq("task_id", taskEntity.getId()));
        // 开始补偿库存锁定值
        for (WareOrderTaskDetailEntity wareOrderTaskDetailEntity : detailList) {
            // 如果工单状态为真正扣除，则补偿
            if (wareOrderTaskDetailEntity.getLockStatus().equals(WareConstant.StockLockStatus.REDUCED.getCode())) {
                // 补偿库存
                wareSkuDao.successPayAndDeductStockRollback(
                        wareOrderTaskDetailEntity.getSkuId(),
                        wareOrderTaskDetailEntity.getSkuNum(),
                        wareOrderTaskDetailEntity.getWareId());
            }
            // 修改库存工单状态
            wareOrderTaskDetailService.update(new UpdateWrapper<WareOrderTaskDetailEntity>().set("lock_status", WareConstant.StockLockStatus.LOCKED.getCode()));
        }
        // 修改订单-库存工单状态
        wareOrderTaskService.update(new UpdateWrapper<WareOrderTaskEntity>().set("lock_status", WareConstant.StockLockStatus.LOCKED.getCode()));
    }
}